package com.example.gw_back_end.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.gw_back_end.domain.PageParam;
import com.example.gw_back_end.domain.PageResult;
import com.example.gw_back_end.domain.SearchParams;
import com.example.gw_back_end.domain.document.TokenDocument;
import com.example.gw_back_end.domain.dto.UsersTypeCount;
import com.example.gw_back_end.domain.entities.User;
import com.example.gw_back_end.mapper.UserMapper;
import com.example.gw_back_end.service.mongodb.TokenService;
import com.example.gw_back_end.service.UserService;
import com.example.gw_back_end.utils.JwtUtil;
import com.example.gw_back_end.utils.Sha3Util;
import com.example.gw_back_end.utils.ThreadLocalUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final JwtUtil jwtUtil;
    private final TokenService tokenService;
    private final UserMapper userMapper;
    private final MongoTemplate mongoTemplate;

    public UserServiceImpl(JwtUtil jwtUtil, TokenService tokenService, UserMapper userMapper, MongoTemplate mongoTemplate) {
        this.jwtUtil = jwtUtil;
        this.tokenService = tokenService;
        this.userMapper = userMapper;
        this.mongoTemplate = mongoTemplate;
    }

    // 用户登录
    @Override
    public String login(String account, String password, String client) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getAccount, account);
        queryWrapper.eq(User::getPassword, Sha3Util.sha3_256(password));
        User user = this.getOne(queryWrapper);
        if (user == null || user.getStatus().equals(1)) {
            return null;
        }

        // 检查当前的用户的账号类型是否与当前的登录平台相符
        boolean isPlatformAllowed = false;
        if (user.getAccountType().equals(0) && "Client".equals(client)) { // 普通用户只能在客户端登录
            isPlatformAllowed = true;
        } else if ((user.getAccountType().equals(1) || user.getAccountType().equals(2)) && ("Vendor".equals(client) || "Client".equals(client))) { // 开发商只能在开发商端登录
            isPlatformAllowed = true;
        } else if (user.getAccountType().equals(3) /*&& "Admin".equals(client)*/) { // 管理员只能在管理端登录
            isPlatformAllowed = true;
        }

        if (!isPlatformAllowed) {
            return null;
        }

        // 防止用户重复登录
        Query query = new Query().addCriteria(Criteria.where("userId").is(user.getId()));
        TokenDocument tokenDocument = mongoTemplate.findOne(query, TokenDocument.class);
        if (tokenDocument != null) {
            System.out.println("用户重复登录，已删除之前的token:" + tokenDocument);
            tokenService.removeToken(tokenDocument.getToken());
        }

        return this.setToken(user);
    }

    // 用户注册
    @Override
    public boolean register(User user) {
        System.out.println(user);
        if (isAccountExists(user.getAccount())) {
            throw new RuntimeException("账号已存在，请更换后重试!");
        }
        user.setPassword(Sha3Util.sha3_256(user.getPassword()));
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        if (user.getAccountType() == null) {
            user.setAccountType(0);
        }
        user.setStatus(0);
        return userMapper.insert(user) > 0;
    }

    // 用户登出
    @Override
    public boolean logout(HttpServletRequest request) {
        String pendingToken = request.getHeader("Authorization");
        if (pendingToken != null && pendingToken.startsWith("Bearer ")) {
            String token = pendingToken.substring(7);
            tokenService.removeToken(token);
            return true;
        } else {
            return false;
        }
    }

    // 邮箱绑定
//    @Override
//    public boolean addEmail(String email) {
//        Map<String,Object> claims = ThreadLocalUtil.get();
//        Integer id = (Integer)claims.get("id");
//        LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
//        lambdaUpdateWrapper.eq(User::getId, id);
//        lambdaUpdateWrapper.set(User::getEmail, email);
//        lambdaUpdateWrapper.set(User::getUpdateTime, LocalDateTime.now());
//        return this.update(lambdaUpdateWrapper);
//    }

    // 电话绑定
//    @Override
//    public boolean addTelephone(String telephone) {
//        Map<String,Object> claims = ThreadLocalUtil.get();
//        Integer id = (Integer)claims.get("id");
//        LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
//        lambdaUpdateWrapper.eq(User::getId, id);
//        lambdaUpdateWrapper.set(User::getTelephone, telephone);
//        lambdaUpdateWrapper.set(User::getUpdateTime, LocalDateTime.now());
//        return this.update(lambdaUpdateWrapper);
//    }

    // 获取当前用户自己的详细信息
    @Override
    public User getInfo() {
        Map<String, Object> claims = ThreadLocalUtil.get();
        Integer id = (Integer) claims.get("id");
        return userMapper.selectById(id);
    }

    // 获取用户列表
    @Override
    public PageResult<User> getUserList(PageParam pageParam, Integer accountType) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (accountType.equals(0)) {
            lambdaQueryWrapper.eq(User::getAccountType, 0);
        } else if (accountType.equals(1)) {
            lambdaQueryWrapper.eq(User::getAccountType, 1).or().eq(User::getAccountType, 2);
        } else if (accountType.equals(3)) {
            lambdaQueryWrapper.eq(User::getAccountType, 3).or().eq(User::getAccountType, 4);
        }
        Page<User> userPage = userMapper.selectPage(new Page<>(pageParam.getPage(), pageParam.getSize()), lambdaQueryWrapper);
        return PageResult.setPageResult(userPage);
    }

    // 获取指定用户的详细信息
    @Override
    public User getUserInfo(Integer id) {
        return userMapper.selectById(id);
    }

    // 更新用户信息（用户自发更新）
    @Override
    public boolean updateInfo(User user) {
        user.setUpdateTime(LocalDateTime.now());
        if (user.getPassword() != null) {
            user.setPassword(Sha3Util.sha3_256(user.getPassword()));
        }
        return userMapper.updateById(user) > 0;
    }

    // 获取平台用户分类数总览
    @Override
    public UsersTypeCount getUsersTypeCount() {

        Integer allTypeCount = userMapper.selectCount(null).intValue();

        List<Integer> accountTypes = Arrays.asList(0, 1, 2, 3); // 具体指明存在的类型编号
        Map<Integer, Long> typeCountMap = new HashMap<>(4);

        for (Integer type : accountTypes) {
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getAccountType, type);
            typeCountMap.put(type, userMapper.selectCount(wrapper));
        }

        Integer type0Count = typeCountMap.getOrDefault(0, 0L).intValue();
        Integer type1Count = typeCountMap.getOrDefault(1, 0L).intValue();
        Integer type2Count = typeCountMap.getOrDefault(2, 0L).intValue();
        Integer type3Count = typeCountMap.getOrDefault(3, 0L).intValue();
        Integer otherTypeCount = allTypeCount - type0Count - type1Count - type2Count - type3Count;

        return new UsersTypeCount(type0Count, type1Count, type2Count, type3Count, otherTypeCount, allTypeCount);
    }

    @Override
    public PageResult<User> searchUser(SearchParams searchParams) {
        String keyword = searchParams.getKeyword();
        PageParam pageParam = searchParams.getPageParam();
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (!searchParams.getValue().isEmpty()) {
            int accountType = searchParams.getValue().get(0);
            switch (accountType) {
                case 1 -> queryWrapper.in(User::getAccountType, Arrays.asList(1, 2));
                case 3 -> queryWrapper.in(User::getAccountType, Arrays.asList(3, 4));
                case 0 -> queryWrapper.eq(User::getAccountType, 0);
                default -> throw new IllegalArgumentException("不支持的账户类型");
            }
        }

        if (StringUtils.isNotBlank(keyword)) {
            queryWrapper.and(wrapper ->
                    wrapper.like(User::getAccount, keyword)
                            .or()
                            .like(User::getUsername, keyword)
                            .or()
                            .like(User::getEmail, keyword)
                            .or()
                            .like(User::getTelephone, keyword)
            );
        }

        if (pageParam == null) {
            List<User> userList = userMapper.selectList(queryWrapper);
            Page<User> userPage = new Page<>();
            userPage.setRecords(userList);
            userPage.setTotal(userList.size());
            userPage.setSize(userList.size());
            userPage.setCurrent(1);
            return PageResult.setPageResult(userPage);
        } else {
            Page<User> userPage = userMapper.selectPage(
                    new Page<>(pageParam.getPage(), pageParam.getSize()),
                    queryWrapper
            );
            return PageResult.setPageResult(userPage);
        }
    }

    @Override
    public boolean confirmPassword(String password) {
        Map<String, Object> claims = ThreadLocalUtil.get();
        Integer id = (Integer) claims.get("id");
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        User user = userMapper.selectById(id);
        return user.getPassword().equals(Sha3Util.sha3_256(password));
    }


    // token设置
    private String setToken(User user) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", user.getId());
        claims.put("account", user.getAccount());
        claims.put("username", user.getUsername());
        claims.put("accountType", user.getAccountType());
        claims.put("status", user.getStatus());
        String rawToken = jwtUtil.generateToken(claims, 1000 * 60 * 60 * 24);
        String token = Sha3Util.sha3_256(rawToken);
        TokenDocument tokenDocument = new TokenDocument();
        tokenDocument.setRawToken(rawToken);
        tokenDocument.setUserId(user.getId());
        tokenDocument.setToken(token);
        tokenService.insertToken(tokenDocument);
        return token;
    }

    // 检查账号是否重复
    private boolean isAccountExists(String account) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getAccount, account);
        return this.count(lambdaQueryWrapper) > 0;
    }

    // 检查用户名是否重复
    private boolean isUsernameExists(String username) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getUsername, username);
        return this.count(lambdaQueryWrapper) > 0;
    }

    // 检查账户密码是否正确（账号密码登录）
//    private User getUserByAccount(String account) {
//        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("account", account);
//        return this.getOne(queryWrapper);
//    }
}
